﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using EzDesk.Apps.Data.ProjectModule;
using EzDesk.Apps.Interface.ProjectModule;
using EzDesk.Apps.Model.ProjectModule;
using EzDesk.Utility.ServiceStatusInfo;
using EzDesk.Utility.Json;
using EzDesk.EzAppApi.Utility;
using EzDesk.Utility.Log;
using EzDesk.Utility.Extensions;
using EzDesk.Utility;
using EzDesk.EzAppApi.Utility;
using EzDesk.Utility.Extensions;

namespace EzDesk.Apps.ServiceImpl.ProjectModule
{
    public partial class ProjectService : IProjectService
    {
        #region [FeedManager 相关方法]
        private string FeedTemplateStr_project_workitemTodo = "project_workitemTodo";

        private string FeedTemplateStr_project_workitemCreated = "project_workitemCreated";
        private string FeedTemplateStr_project_workitemNewOwner = "project_workitemNewOwner";
        private string FeedTemplateStr_project_workitemFinished = "project_workitemFinished";
        private string FeedTemplateStr_project_workitemExpired = "project_workitemExpired";
        private string FeedTemplateStr_project_workitemConfirmed = "project_workitemConfirmed";
        private string FeedTemplateStr_project_workitemContentUpdated = "project_workitemContentUpdated";
        private string FeedTemplateStr_project_statistics = "project_statistics";
        private string FeedTemplateStr_project_workitemPostponed = "project_workitemPostponed";

        private Guid sendproject_workitemCreated(string memberstring, Workitem workitem)
        {
            bool isNotification = memberstring == workitem.OwnerId.ToString() &&
                                  workitem.Status == WorkitemStatus.WaitingForConfirm;
            var feedData = getWorkitemCreatedFeedData(memberstring, workitem, isNotification);

            var feedId = _ezApiClient.SendFeed(
                 FeedTemplateStr_project_workitemCreated,
                 JsonHelper.ConvertToJson(feedData),
                 memberstring
                 );

            if (isNotification)
            {
                _ezApiClient.UpdatePersonalFeedType(feedId, memberstring, "notification");
                _ezApiClient.SetFeedRecord(workitem.Id, FeedTemplateStr_project_workitemCreated,
                                           workitem.OwnerId.ToString(), feedId, null);
            }
            return feedId;
        }
        private Dictionary<string, string> getWorkitemCreatedFeedData(string memberstring, Workitem workitem, bool isNotification)
        {
            var isFirst = true;
            var titleContent = getTitleContent(workitem, ref isFirst);
            var ownerContent = getOwnerContent(workitem, ref isFirst);
            var confirmLink = isNotification ? getConfirmLink(workitem, ref isFirst) : "";

            var feedData = new Dictionary<string, string>
                               {
                                   {"workitemId", workitem.Id.ToString()},
                                   {"titleContent", titleContent},
                                   {"ownerContent", ownerContent},
                                   {"confirmLink", confirmLink}
                               };


            feedData.Merge(getWorkitemAdditionalFeedData(workitem, ref isFirst));

            return feedData;
        }

        private void sendproject_workitemNewOwner(string memberstring, Workitem workitem)
        {
            var feedData = getWorkitemNewOwnerFeedData(workitem);

            _ezApiClient.SendFeed(
                 FeedTemplateStr_project_workitemNewOwner,
                 JsonHelper.ConvertToJson(feedData),
                 memberstring
                 );
        }

        private Dictionary<string, string> getWorkitemNewOwnerFeedData(Workitem workitem)
        {
            var isFirst = true;
            var titleContent = getTitleContent(workitem, ref isFirst);
            var ownerContent = getOwnerContent(workitem, ref isFirst);
            var feedData = new Dictionary<string, string>
                               {
                                   {"workitemId", workitem.Id.ToString()},
                                   {"titleContent", titleContent},
                                   {"ownerContent", ownerContent},
                               };
            feedData.Merge(getWorkitemAdditionalFeedData(workitem, ref isFirst, false));
            return feedData;

        }
        private void sendproject_workitemFinished(string memberstring, Workitem workitem, Guid actorId)
        {
            var feedData = getWorkitemFinishedFeedData(memberstring, workitem, actorId);

            _ezApiClient.SendFeed(
                 FeedTemplateStr_project_workitemFinished,
                 JsonHelper.ConvertToJson(feedData),
                 memberstring
                 );
        }

        private Dictionary<string, string> getWorkitemFinishedFeedData(string memberstring, Workitem workitem, Guid actorId)
        {
            var isFirst = true;

            var actor = _ezApiClient.GetSimpleUserById(actorId);

            var titleContent = getTitleContent(workitem, ref isFirst, actor.Name + " 完成了", "任务");
            var ownerContent = workitem.OwnerId != actorId ? getOwnerContent(workitem, ref isFirst) : "";

            var feedData = new Dictionary<string, string>
                               {
                                   {"workitemId", workitem.Id.ToString()},
                                   {"titleContent", titleContent},
                                   {"ownerContent", ownerContent},
                               };

            feedData.Merge(getWorkitemAdditionalFeedData(workitem, ref isFirst, false, true, false));

            return feedData;
        }

        private void sendproject_workitemExpired(string memberstring, Workitem workitem)
        {
            var feedData = getWorkitemExpired(workitem);

            _ezApiClient.SendFeed(
                 FeedTemplateStr_project_workitemExpired,
                 JsonHelper.ConvertToJson(feedData),
                 memberstring
                 );
        }

        private Dictionary<string, string> getWorkitemExpired(Workitem workitem)
        {
            var isFirst = true;
            var titleContent = getTitleContent(workitem, ref isFirst, null, "任务已经到期");
            var feedData = new Dictionary<string, string>
                               {
                                   {"workitemId", workitem.Id.ToString()},
                                   {"titleContent", titleContent},
                               };
            feedData.Merge(getWorkitemAdditionalFeedData(workitem, ref isFirst, false));
            return feedData;
        }
        private void sendproject_workitemConfirmed(string memberstring, Workitem workitem)
        {
            var feedData = getWorkitemConfirmedFeedData(memberstring, workitem);

            _ezApiClient.SendFeed(
                 FeedTemplateStr_project_workitemConfirmed,
                 JsonHelper.ConvertToJson(feedData),
                 memberstring
                 );
        }
        private Dictionary<string, string> getWorkitemConfirmedFeedData(string memberstring, Workitem workitem)
        {
            var isFirst = true;

            var owner = _ezApiClient.GetSimpleUserById(workitem.OwnerId.Value);

            var titleContent = getTitleContent(workitem, ref isFirst, owner.Name + " 确认收到", "任务");
            var feedData = new Dictionary<string, string>
                               {
                                   {"workitemId", workitem.Id.ToString()},
                                   {"titleContent", titleContent},
                               };
            feedData.Merge(getWorkitemAdditionalFeedData(workitem, ref isFirst, false));

            return feedData;
        }

        private void sendproject_workitemContentUpdated(string memberstring, Workitem oldWorkitem, Workitem workitem, Guid actorId)
        {
            var feedData = getWorktiemContentUpdatedFeedData(oldWorkitem, workitem, actorId);

            _ezApiClient.SendFeed(
                 FeedTemplateStr_project_workitemContentUpdated,
                 JsonHelper.ConvertToJson(feedData),
                 memberstring
                 );
        }

        private object getWorktiemContentUpdatedFeedData(Workitem oldWorkitem, Workitem workitem, Guid actorId)
        {
            var isFirst = true;
            var actor = _ezApiClient.GetSimpleUserById(actorId);

            var titleContent = getTitleContent(workitem, ref isFirst, actor.Name + " 更新了", "任务");

            var descriptionChangeContent = "";
            if (oldWorkitem.Description != workitem.Description)
            {
                descriptionChangeContent = getNewLineSymbol(ref isFirst) +
                                           "更新了描述：{0}".FormatString(workitem.Description);
            }

            var feedData = new Dictionary<string, string>
                               {
                                   {"workitemId", workitem.Id.ToString()},
                                   {"titleContent", titleContent},
                                   {"descriptionChangeContent", descriptionChangeContent},
                               };
            feedData.Merge(getWorkitemAdditionalFeedData(workitem, ref isFirst, false));

            return feedData;
        }


        /// <summary>
        /// 将一条Workitem添加到被执行人的TODO列表中
        /// </summary>
        /// <param name="memberstring"></param>
        /// <param name="workitem"></param>
        private void send_workitemTodo(string memberstring, Workitem workitem)
        {
            var feedData = getWorkitemToDoFeedData(workitem);

            var feedId = _ezApiClient.SendFeed(
                FeedTemplateStr_project_workitemTodo,
                JsonHelper.ConvertToJson(feedData),
                memberstring
                );
            _ezApiClient.SetFeedRecord(workitem.Id, FeedTemplateStr_project_workitemTodo, memberstring, feedId, null);
        }
        private Dictionary<string, string> getWorkitemToDoFeedData(Workitem workitem)
        {
            bool isFirst = true;
            var feedData = new Dictionary<string, string>
            {
                {"workitemId", workitem.Id.ToString()},
                {"titleContent", workitem.Title},
            };
            feedData.Merge(getWorkitemAdditionalFeedData(workitem, ref isFirst));
            return feedData;
        }



        /// <summary>
        /// 更新工作任务内容时更新工作任务的todo
        /// </summary>
        /// <param name="memberstring"></param>
        /// <param name="workitem"></param>
        private void updateWorkItemTodoFeed_changeContent(string memberstring, Workitem workitem)
        {
            var feedIdStr = _ezApiClient.GetFeedRecord(workitem.Id, FeedTemplateStr_project_workitemTodo,
                                                    memberstring);

            var newFeedData = getWorkitemToDoFeedData(workitem);
            _ezApiClient.UpdateFeedsData(feedIdStr, JsonHelper.ConvertToJson(newFeedData));
            _ezApiClient.SetFeedsIsRead(feedIdStr, memberstring, true);
        }

        private void removeWorkitemConfirmNotification(Guid workitemId, Guid ownerId)
        {
            var feedIdStr = _ezApiClient.GetFeedRecord(workitemId, FeedTemplateStr_project_workitemCreated,
                                                       ownerId.ToString());
            Guid feedId;
            if (Guid.TryParse(feedIdStr, out feedId))
            {
                _ezApiClient.UpdatePersonalFeedType(feedId, ownerId.ToString(), "update");
                var feedData = new Dictionary<string, string>
                                   {
                                       {"confirmLink", ""},
                                   };
                _ezApiClient.UpdatePersonalFeedData(feedId, ownerId.ToString(),
                                                    JsonHelper.ConvertToJson(feedData));
            }
        }


        private void sendChangeWorkitemOwnerFeeds(Workitem newWorkitem, Guid oldOwnerId)
        {
            EzDeskProjectContainer.Go(
                container =>
                {
                    // 删掉原来负责人的ToDo
                    var feedIdStr = _ezApiClient.GetFeedRecord(newWorkitem.Id, FeedTemplateStr_project_workitemTodo,
                                                               oldOwnerId.ToString());
                    _ezApiClient.SetFeedsIsAvailable(feedIdStr, oldOwnerId.ToString(), false);

                    // 发一条新的ToDo给新的负责人
                    send_workitemTodo(newWorkitem.OwnerId.ToString(), newWorkitem);

                    // 如果原来的负责人有Notification，那么变成Update
                    removeWorkitemConfirmNotification(newWorkitem.Id, oldOwnerId);

                    // 发送一条 负责人更改的Feed

                    // 如果与项目相关，给项目组成员发，
                    var newOwnerMemberstring = "";
                    if (newWorkitem.ProjectId.HasValue)
                    {
                        newOwnerMemberstring =
                            container.ProjectSet.First(p => p.Id == newWorkitem.ProjectId.Value).MemberString;
                    }
                    // 要给原来的负责人发
                    newOwnerMemberstring = EzDeskAppApiHelper.MemberStringHelper.JoinUserId(
                            newOwnerMemberstring, oldOwnerId);
                    // 如果追踪，还给任务创建者发
                    if (newWorkitem.IsTrace)
                    {
                        newOwnerMemberstring = EzDeskAppApiHelper.MemberStringHelper.JoinUserId(
                            newOwnerMemberstring, newWorkitem.CreatorId);
                    }
                    sendproject_workitemNewOwner(newOwnerMemberstring, newWorkitem);

                    // 给新的负责人发一条：新的任务Feed
                    sendproject_workitemCreated(newWorkitem.OwnerId.ToString(), newWorkitem);
                });
        }


        private void sendproject_statistics()
        {
            var memberstring = "everyone";
            var date = DateTime.Now.AddDays(-7).Date;
            var startWeek = date.AddDays(0 - Convert.ToInt32(date.DayOfWeek.ToString("d")));
            var endWeek = startWeek.AddDays(6);

            var dateEpoch = date.ToEpoch().ToString();
            var dateContent = "{0} 至 {1}".FormatString(startWeek.ToFullDate(), endWeek.ToFullDate());
            var rankContent = "";
            var feedData = new Dictionary<string, string>
                   {
                      {"dateEpoch", dateEpoch},
                      {"dateContent", dateContent},
                      {"rankContent", rankContent},
                   };

            var feedId = _ezApiClient.SendFeed(
                 FeedTemplateStr_project_statistics,
                 JsonHelper.ConvertToJson(feedData),
                 memberstring, isAvailable: false
                 );
            var statistics = getWorkitemStatisticses(startWeek, endWeek, memberstring);
            foreach (var workitemStatisticse in statistics)
            {
                _ezApiClient.UpdatePersonalFeedData(
                    feedId,
                    workitemStatisticse.TargetUser.Id.ToString(),
                    JsonHelper.ConvertToJson(
                        new Dictionary<string, string>
                            {
                                {"rankContent", (workitemStatisticse.Index + 1).ToString()}
                            })
                    );
            }

            _ezApiClient.SetFeedIsAvailable(feedId, memberstring, true);
        }

        private void sendproject_workitemPostponed(String memberstring, Workitem workitem)
        {
            var feedData = getWorkitemPostponedFeedData(workitem);

            _ezApiClient.SendFeed(
                FeedTemplateStr_project_workitemPostponed,
                JsonHelper.ConvertToJson(feedData),
                memberstring
                );

        }

        private Dictionary<string, string> getWorkitemPostponedFeedData(Workitem workitem)
        {
            var isFirst = true;

            var titleContent = getTitleContent(workitem, ref isFirst, null, "任务 被延期到了" + workitem.PlanOn.Value.ToFullDate());
            var ownerContent = getOwnerContent(workitem, ref isFirst);

            var feedData = new Dictionary<string, string>
                               {
                                   {"workitemId", workitem.Id.ToString()},
                                   {"titleContent", titleContent},
                                   {"ownerContent", ownerContent}
                               };
            feedData.Merge(getWorkitemAdditionalFeedData(workitem, ref isFirst, true, true, false));

            return feedData;
        }
        #region get content for feeds


        private Dictionary<string, string> getWorkitemAdditionalFeedData(
            Workitem workitem, ref bool isFirst,
            bool includeTraceContent = true,
            bool includeProjectContent = true,
            bool includePlanOnContent = true
            )
        {
            var traceContent = "";
            var projectContent = "";
            var planOnContent = "";

            if (workitem.IsTrace && includeTraceContent)
            {
                traceContent = getTraceContent(workitem, ref isFirst);
            }
            if (workitem.ProjectId != null && includeProjectContent)
            {
                projectContent = getProjectContent(workitem, ref isFirst);
            }
            if (workitem.PlanOn != null && includePlanOnContent)
            {
                planOnContent = getPlanOnContent(workitem, ref isFirst);
            }

            var feedData = new Dictionary<string, string>
            {
                {"traceContent", traceContent},
                {"projectContent", projectContent},
                {"planOnContent", planOnContent},
            };
            return feedData;
        }

        private string getNewLineSymbol(ref bool isFirst)
        {
            var content = "";
            if (isFirst)
            {
                isFirst = false;
            }
            else
            {
                content = "<ez:br/>";
            }
            return content;
        }

        private string getTitleContent(Workitem workitem, ref bool isFirst, string prefixStr = "", string suffixStr = "")
        {
            var titleContentFormatBuilder = new StringBuilder("\"{0}\"");
            if (!string.IsNullOrEmpty(prefixStr))
            {
                titleContentFormatBuilder.Insert(0, prefixStr + " ");
            }
            if (!string.IsNullOrEmpty(suffixStr))
            {
                titleContentFormatBuilder.Append(" " + suffixStr);
            }
            string titleContent = getNewLineSymbol(ref isFirst) +
                           string.Format(titleContentFormatBuilder.ToString(), workitem.Title);
            return titleContent;
        }

        private string getConfirmLink(Workitem workitem, ref bool isFirst)
        {
            string confirmLink = getNewLineSymbol(ref isFirst) +
                              "<ez:target funcurl=\"/project/ConfirmWorkitem/{0}\"><ez:text>确认收到任务</ez:text></ez:target>"
                                  .FormatString(workitem.Id.ToString());

            return confirmLink;
        }

        private string getOwnerContent(Workitem workitem, ref bool isFirst)
        {
            string ownerContent;
            if (workitem.OwnerId != null)
            {
                var owner = _ezApiClient.GetSimpleUserById(workitem.OwnerId.Value);
                ownerContent = getNewLineSymbol(ref isFirst) +
                               "任务负责人 {0}".FormatString(owner.Name);
            }
            else
            {
                ownerContent = getNewLineSymbol(ref isFirst) + "还没有指定负责人";
            }
            return ownerContent;
        }

        private string getPlanOnContent(Workitem workitem, ref bool isFirst)
        {
            string planOnContent;
            planOnContent = getNewLineSymbol(ref isFirst) +
                            string.Format("在 {0} 到期", workitem.PlanOn.Value.ToFullDate());
            return planOnContent;
        }

        private string getTraceContent(Workitem workitem, ref bool isFirst)
        {
            var creator = _ezApiClient.GetSimpleUserById(workitem.CreatorId);
            var traceContent = getNewLineSymbol(ref isFirst) + string.Format("{0} 正在追踪这个任务", creator.Name);

            return traceContent;
        }

        private string getProjectContent(Workitem workitem, ref bool isFirst)
        {
            var projectId = workitem.ProjectId.Value;

            Project project = null;
            Task task = null;
            EzDeskProjectContainer.Go(
                container =>
                {
                    project = container.ProjectSet.FirstOrDefault(p => p.Id == projectId);
                    if (workitem.TaskId != null)
                    {
                        task = container.TaskSet.FirstOrDefault(p => p.Id == workitem.TaskId.Value);
                    }
                });

            var projectContent = getNewLineSymbol(ref isFirst) +
                             string.Format("与 {0} 项目{1}关联", project.Name, task == null
                                                                              ? ""
                                                                              : string.Format("({0})", task.Name));
            return projectContent;
        }
        #endregion


        #endregion


        #region [ private methods ]


        private void sendAddWorkitemFeeds(Workitem workitem)
        {
            EzDeskProjectContainer.Go(
                container =>
                {
                    if (workitem.ProjectId.HasValue)
                    {
                        var projectMemberstring =
                            container.ProjectSet.First(p => p.Id == workitem.ProjectId).MemberString;

                        if (workitem.IsTrace && workitem.OwnerId.HasValue)
                        {
                            // 如果需要追踪，那么这条feed不发给任务负责人
                            projectMemberstring =
                                EzDeskAppApiHelper.MemberStringHelper.RemoveUserId(projectMemberstring,
                                                                                   workitem.OwnerId.Value);
                        }
                        sendproject_workitemCreated(projectMemberstring, workitem);
                    }

                    // 如果任务需要追踪，那么给任务负责人发送一条确认的Notification
                    if (workitem.IsTrace && workitem.OwnerId.HasValue)
                    {
                        sendproject_workitemCreated(workitem.OwnerId.ToString(), workitem);
                    }

                    // 给任务负责人发送一条ToDo
                    if (workitem.OwnerId.HasValue)
                    {
                        send_workitemTodo(workitem.OwnerId.ToString(), workitem);
                    }
                });
        }

        private Workitem getWorkitemById(Guid workitemId)
        {
            var item = EzDeskProjectContainer.Go(
                container =>
                {
                    var entity = container.WorkitemSet.FirstOrDefault(p => p.Id == workitemId);
                    container.LoadProperty(entity, e => e.Project);
                    return entity;
                });

            if (item == null)
            {
                throw new Exception("没有找到对应的工作任务");
            }
            return item;
        }

        private List<WorkitemStatistics> getWorkitemStatisticses(DateTime startDay, DateTime endDay, string memberstring)
        {
            return EzDeskProjectContainer.Go(
                db =>
                {
                    startDay = startDay.Date;
                    endDay = endDay.Date.AddDays(1);

                    var userList =
                        _ezApiClient.GetAllUsersByMemberString(memberstring);
                    var userIdList = userList.Select(p => p.Id).ToList();
                    var finishedWorkitems =
                        db.WorkitemSet.Where(wi => wi.IsFinished &&
                                                   userIdList.Contains(wi.OwnerId.Value) &&
                                                   wi.FinishOn >= startDay && wi.FinishOn < endDay)
                            .ToList();
                    var createdWorkitems =
                        db.WorkitemSet.Where(wi => userIdList.Contains(wi.CreatorId) &&
                                                   wi.CreateOn >= startDay && wi.CreateOn < endDay)
                            .ToList();
                    return userList.Select(
                        user => new WorkitemStatistics()
                        {
                            TargetUser = user,
                            CreatedWorkitemCount =
                                createdWorkitems.Where(
                                    wi => wi.CreatorId == user.Id).Count(),
                            FinishedWorkitemCount =
                                finishedWorkitems.Where(
                                    wi => wi.OwnerId == user.Id).Count(),
                            TotalPoints =
                                finishedWorkitems.Where(
                                    wi => wi.OwnerId == user.Id).Sum(
                                        p => p.Points),
                        })
                        .OrderBy(p => p.TargetUser.Dept.DeptName)
                        .OrderByDescending(p => p.TotalPoints)
                        .ToList()
                        .FillIndex();
                });
        }

        #endregion


        #region [ public methods ]
        public StatusInfo<Guid> AddWorkitem(Workitem workitem)
        {
            return StatusInfo.Wrap(
                () => EzDeskProjectContainer.GoAndSave(
                    container =>
                    {
                        {
                            var newWorkitemId = Guid.NewGuid();
                            workitem.Id = newWorkitemId;
                            workitem.CreateOn = DateTime.Now;
                            workitem.UpdateOn = workitem.CreateOn;

                            if (workitem.OwnerId == null)
                            {
                                workitem.Status = WorkitemStatus.Ready;
                            }
                            else
                            {
                                workitem.Status = workitem.IsTrace && workitem.OwnerId != workitem.CreatorId
                                                      ? WorkitemStatus.WaitingForConfirm
                                                      : WorkitemStatus.Ongoing;
                            }

                            container.WorkitemSet.AddObject(workitem);
                            container.SaveChanges();

                            // 如果任务跟项目有关，那么给项目成员发送一条Feed)
                            sendAddWorkitemFeeds(workitem);

                            return newWorkitemId;
                        }
                    })
                );
        }


        public StatusInfo<Guid> AddFinishedWorkitem(Workitem workitem)
        {
            return StatusInfo.Wrap(
                () =>
                {
                    var newWorkitemId = Guid.NewGuid();
                    workitem.Id = newWorkitemId;
                    workitem.IsFinished = true;
                    workitem.CreateOn = DateTime.Now;
                    workitem.UpdateOn = workitem.CreateOn;
                    workitem.Status = WorkitemStatus.Completed;
                    
                    EzDeskProjectContainer.GoAndSave(
                        entity => entity.WorkitemSet.AddObject(workitem));
                    return newWorkitemId;
                });
        }

        #region [ query methods ]
        public StatusInfo<List<Workitem>> GetWorkitemByIds(List<Guid> guids)
        {
            var guidSB = new StringBuilder();
            return StatusInfo.Wrap(
            () => EzDeskProjectContainer.Go(db =>
            {
                guids.ForEach(g => guidSB.Append(g));
                var guidJoinString = guidSB.ToString();
                var query = db.WorkitemSet.Where(wi => guidJoinString.Contains(wi.TaskId.ToString()));
                foreach (var workitem in query)
                {
                    db.LoadProperty(workitem, wi => wi.Project);
                    db.LoadProperty(workitem, wi => wi.Task);

                }
                return query.ToList();
            }));
        }

        public StatusInfo<List<Workitem>> GetWorkitems(
            Guid? ownerId, Guid? creatorId, Guid? projectId, Guid? taskId,
            WorkitemStatus? status,
            bool? isFinished,
            DateTime? startCreateOn, DateTime? endCreateOn,
            DateTime? startFinishOn, DateTime? endFinishOn,
            int? maxCount)
        {
            return StatusInfo.Wrap(
                () =>
                {
                    var workitems = EzDeskProjectContainer.Go(
                        container =>
                        {
                            IQueryable<Workitem> query = container.WorkitemSet;
                            if (ownerId.HasValue)
                            {
                                query = query.Where(p => p.OwnerId == ownerId.Value);
                            }
                            if (creatorId.HasValue)
                            {
                                query = query.Where(p => p.CreatorId == creatorId.Value);
                            }
                            if (projectId.HasValue)
                            {
                                query = query.Where(p => p.ProjectId == projectId.Value);
                            }
                            if (taskId.HasValue)
                            {
                                query = query.Where(p => p.TaskId == taskId.Value);
                            }
                            if (isFinished.HasValue)
                            {
                                query = query.Where(p => p.IsFinished == isFinished.Value);
                            }
                            if (startCreateOn.HasValue)
                            {
                                query = query.Where(p => p.CreateOn >= startCreateOn.Value);
                            }
                            if (endCreateOn.HasValue)
                            {
                                query = query.Where(p => p.CreateOn <= endCreateOn.Value);
                            }
                            if (startFinishOn.HasValue)
                            {
                                query = query.Where(p => p.FinishOn >= startFinishOn.Value);
                            }
                            if (endFinishOn.HasValue)
                            {
                                query = query.Where(p => p.FinishOn <= endFinishOn.Value);
                            }
                            if (status.HasValue)
                            {
                                query = query.Where(p => p.StatusValue == (int)status);
                            }
                            if (maxCount.HasValue)
                            {
                                query = query.Take(maxCount.Value);
                            }
                            foreach (var workitem in query)
                            {
                                container.LoadProperty(workitem, wi => wi.Project);
                                container.LoadProperty(workitem, wi => wi.Task);
                            }
                            return query.ToList();
                        });
                    return workitems;
                });
        }

        public StatusInfo<Workitem> GetWorkitem(Guid workitemId)
        {
            return StatusInfo.Wrap(
                () =>
                {
                    var item = getWorkitemById(workitemId);
                    return item;
                });
        }


        public StatusInfo<List<WorkitemStatistics>> GetWorkitemStatistics(string memberstring, DateTime startDay, DateTime endDay)
        {
            return StatusInfo.Wrap(
                () => getWorkitemStatisticses(startDay, endDay, memberstring)
                );
        }



        #endregion

        public StatusInfo ConfirmWorkItem(Guid workitemId, Guid actorId)
        {
            return StatusInfo.Wrap(
                () => EzDeskProjectContainer.GoAndSave(container =>
                {
                    var workitem =
                       container.WorkitemSet.FirstOrDefault(w => w.Id == workitemId);

                    if (workitem.OwnerId != actorId)
                        throw new Exception("只有任务的负责人才能确认收到任务!");

                    workitem.StatusValue = (int)WorkitemStatus.Ongoing;
                    workitem.UpdateOn = DateTime.Now;

                    container.SaveChanges();

                    // 修改 负责人收到的那条Notification
                    removeWorkitemConfirmNotification(workitem.Id, workitem.OwnerId.Value);

                    // 如果追踪，给创建者发个消息)
                    if (workitem.IsTrace)
                    {
                        var memberstring = workitem.CreatorId.ToString();
                        sendproject_workitemConfirmed(memberstring, workitem);
                    }

                }));

        }



        //TODO: Update to Interface
        public StatusInfo CancelWorkItem(Guid workitemId, Guid actorId)
        {
            return StatusInfo.Wrap(
                () => EzDeskProjectContainer.GoAndSave(container =>
                {
                    var workitem =
                        container.WorkitemSet.FirstOrDefault(w => w.Id == workitemId);
                    //todo: 修改状态
                    container.SaveChanges();


                }));
        }

        public StatusInfo FinishWorkitem(Guid workitemId, Guid actorId, int estimatePoint)
        {
            return StatusInfo.Wrap(
                () =>
                EzDeskProjectContainer.GoAndSave(
                    container =>
                    {
                        var workitem =
                            getWorkitemById(workitemId);
                        //if (workitem.OwnerId != actorId)
                        //{
                        //    throw new Exception("只有这个任务的负责人才能完成这个任务");
                        //}
                        if (workitem.IsFinished)
                        {
                            throw new Exception("这个任务已经被完成了");
                        }
                        if (workitem.OwnerId == null)
                        {
                            workitem.OwnerId = actorId;
                        }
                        workitem.FinishOn = DateTime.Now;
                        workitem.IsFinished = true;
                        workitem.StatusValue =
                            (int)WorkitemStatus.Completed;
                        workitem.Points = estimatePoint;
                        workitem.UpdateOn =
                            workitem.FinishOn;


                        container.WorkitemSet.Attach(
                            workitem);
                        container.ObjectStateManager.
                            ChangeObjectState(workitem,
                                              EntityState.
                                                  Modified);


                        // 更新workitem Todo的内容
                        updateWorkItemTodoFeed_changeContent
                            (workitem.OwnerId.ToString(),
                             workitem);

                        // 发送任务完成的通知

                        string memberstring = "";
                        // 包含项目组成员
                        if (workitem.ProjectId != null)
                        {
                            memberstring = container.ProjectSet.First(p => p.Id == workitem.ProjectId).MemberString;
                        }
                        // 包含项目负责人
                        if (workitem.OwnerId.HasValue)
                        {
                            memberstring = EzDeskAppApiHelper.MemberStringHelper.JoinUserId(memberstring,
                                                                                            workitem.OwnerId.Value);
                        }
                        // 如果需要追踪 包含项目创建者
                        if (workitem.IsTrace)
                        {
                            memberstring = EzDeskAppApiHelper.MemberStringHelper.JoinUserId(memberstring, workitem.CreatorId);
                        }
                        if (!string.IsNullOrEmpty(memberstring))
                        {
                            sendproject_workitemFinished(memberstring, workitem, actorId);
                        }
                    })
                );
        }


        public StatusInfo PostponeWorkitem(Guid workitemId, DateTime newPlanOn)
        {
            return StatusInfo.Wrap(
                   () => EzDeskProjectContainer.GoAndSave(
                       container =>
                       {
                           var workitem = getWorkitemById(workitemId);

                           workitem.PlanOn = newPlanOn;
                           workitem.StatusValue = (int)WorkitemStatus.Ongoing;

                           container.WorkitemSet.Attach(
                               workitem);
                           container.ObjectStateManager.
                               ChangeObjectState(workitem,
                                                 EntityState.
                                                     Modified);

                           string memberstring = "";
                           // 包含项目负责人
                           if (workitem.OwnerId.HasValue)
                           {
                               memberstring = EzDeskAppApiHelper.MemberStringHelper.JoinUserId(memberstring,
                                                                                               workitem.OwnerId.Value);
                           }
                           // 如果需要追踪 包含项目创建者
                           if (workitem.IsTrace)
                           {
                               memberstring = EzDeskAppApiHelper.MemberStringHelper.JoinUserId(memberstring, workitem.CreatorId);
                           }
                           // 发送feed
                           sendproject_workitemPostponed(memberstring, workitem);

                       }));

     

        }





        public StatusInfo UpdateWorkitem(Workitem workitem, Guid actorId)
        {
            return StatusInfo.Wrap(
                () => EzDeskProjectContainer.Go(
                    container =>
                    {
                        var oldWorkitem =
                            container.WorkitemSet
                                .FirstOrDefault(p => p.Id == workitem.Id);

                        var newWorkitem = new Workitem()
                                              {
                                                  Id = oldWorkitem.Id,
                                                  CreateOn = oldWorkitem.CreateOn,
                                                  CreatorId = oldWorkitem.CreatorId,
                                                  StatusValue = oldWorkitem.StatusValue,
                                                  IsFinished = oldWorkitem.IsFinished,
                                                  FinishOn = oldWorkitem.FinishOn,

                                                  Points = workitem.Points,
                                                  PlanOn = workitem.PlanOn,
                                                  OwnerId = workitem.OwnerId,
                                                  ProjectId = workitem.ProjectId,
                                                  Description = workitem.Description,
                                                  Title = workitem.Title,
                                                  TaskId = workitem.TaskId,
                                                  IsTrace = workitem.IsTrace,
                                              };

                        bool isOwnerChanged = false;

                        // 如果原来有负责人并且修改了负责人
                        if (oldWorkitem.OwnerId.HasValue && newWorkitem.OwnerId.HasValue &&
                            oldWorkitem.OwnerId != newWorkitem.OwnerId)
                        {
                            if (newWorkitem.OwnerId == newWorkitem.CreatorId)
                            {
                                newWorkitem.Status = WorkitemStatus.Ongoing;
                            }

                            // 当做给新的负责人指派了任务，发送各种Feed
                            sendChangeWorkitemOwnerFeeds(newWorkitem, oldWorkitem.OwnerId.Value);
                            isOwnerChanged = true;
                        }

                        //如果原来没有负责人，现在有了负责人
                        if (oldWorkitem.OwnerId == null && newWorkitem.OwnerId != null)
                        {
                            newWorkitem.Status = newWorkitem.IsTrace && newWorkitem.OwnerId != newWorkitem.CreatorId
                                                     ? WorkitemStatus.WaitingForConfirm
                                                     : WorkitemStatus.Ongoing;

                            // 如果需要追踪，给创建者发一条负责人改变的feed
                            if (workitem.IsTrace)
                            {
                                sendproject_workitemNewOwner(workitem.CreatorId.ToString(), newWorkitem);
                            }

                            // 当做给新的负责人指派了任务，发送各种Feed
                            sendAddWorkitemFeeds(newWorkitem);
                            isOwnerChanged = true;
                        }

                        // 如果修改了任务内容
                        if (oldWorkitem.Title != newWorkitem.Title ||
                            oldWorkitem.ProjectId != newWorkitem.ProjectId ||
                            oldWorkitem.TaskId != newWorkitem.TaskId ||
                            oldWorkitem.PlanOn != newWorkitem.PlanOn ||
                            oldWorkitem.Description != newWorkitem.Description
                            )
                        {
                            if (newWorkitem.OwnerId.HasValue)
                            {
                                updateWorkItemTodoFeed_changeContent(newWorkitem.OwnerId.ToString(), newWorkitem);
                            }
                            // 如果owner没有变化，那么发送一大堆关于workitem内容变化的Feed
                            if (!isOwnerChanged)
                            {
                                // 寻找发送目标。。。
                                var memberstring = "";
                                if (newWorkitem.ProjectId.HasValue)
                                {
                                    memberstring =
                                        container.ProjectSet.First(p => p.Id == newWorkitem.ProjectId.Value).
                                            MemberString;
                                }
                                if (newWorkitem.OwnerId.HasValue)
                                {
                                    memberstring = EzDeskAppApiHelper.MemberStringHelper.JoinUserId(memberstring,
                                                                                     newWorkitem.OwnerId.Value);
                                }
                                if (newWorkitem.IsTrace)
                                {
                                    memberstring =
                                        EzDeskAppApiHelper.MemberStringHelper.JoinUserId(memberstring,
                                                                                         newWorkitem.CreatorId);
                                }
                                sendproject_workitemContentUpdated(memberstring, oldWorkitem, newWorkitem, actorId);
                            }
                        }

                        container.WorkitemSet.ApplyCurrentValues(newWorkitem);
                        container.SaveChanges();

                    }));
        }


        // todo: 完善这个功能
        public StatusInfo SendDailyWorkBlog()
        {
            var today = DateTime.Today;
            return StatusInfo.Wrap(
            () => EzDeskProjectContainer.Go(container =>
            {
                var workitemCompletedToday =
                    container.WorkitemSet.Where(
                        workitem => workitem.FinishOn > today && workitem.FinishOn < today.AddDays(1));
                var dailyWorks = container.DailyWorksSet.Where(
                    dailyWork =>
                    dailyWork.Day >= today && dailyWork.Day < today.AddDays(1)
                    );

            }));
        }

        public StatusInfo CheckTimeOutWorkItems()
        {
            return StatusInfo.Wrap(
            () => EzDeskProjectContainer.Go(container =>
            {
                var now = DateTime.Now;
                var workitemList = container.WorkitemSet.Where(w => w.PlanOn < now && !w.IsFinished).ToList();

                foreach (var workItem in workitemList)
                {
                    workItem.Status = WorkitemStatus.Expired;
                    // 发feed
                    string memberstring = "";
                    if (workItem.OwnerId.HasValue)
                    {
                        memberstring = EzDeskAppApiHelper.MemberStringHelper.JoinUserId(memberstring,
                                                                         workItem.OwnerId.Value);
                    }
                    if (workItem.IsTrace)
                    {
                        memberstring =
                            EzDeskAppApiHelper.MemberStringHelper.JoinUserId(memberstring,
                                                                             workItem.CreatorId);
                    }

                    sendproject_workitemExpired(memberstring, workItem);
                }
                container.SaveChanges();


            }));
        }

        public void CheckStatisticsReport()
        {
            if (DateTime.Now.DayOfWeek == DayOfWeek.Sunday)
            {
                sendproject_statistics();
            }
        }

        #endregion
    }
}
